import sys
sys.path.append("../")
from model.ExamModel import *
from model.CommonDb import *
from model.StockBaseInfo import *
from services.BaseService import *
from services.self_market.AccountExchangeService import *
from services.self_market.StockHoldsDetailService import *
from services.self_market.AccountDetailService import *
import httpx
import akshare as ak
from frameworks.utils.RedisUtil import *
import json
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import MultipleLocator
import datetime

class CodeService(BaseService):
    def __init__(self):
        super(CodeService, self).__init__()
        self.db = CommonDb("codes","stock")
        self.today = datetime.datetime.now().strftime("%Y-%m-%d")

    def updateCode(self):
        model = CodesModel()
        return model.updateCodes()

    def updateMaxval20(self,orderkey,startday):
        sql = "update codes a left join (select code,max(close) as max_close from (select code,close from day_kline_"+str(orderkey)+" where trade_date >='"+startday+"') c group by c.code) b on a.code = b.code  set a.maxval20 = b.max_close where b.code is not null;"
        return self.db.executeUpdate(sql)

    def getCodes(self):
        return self.db.selectAll("1","* order by id ",True)

    def getDivCodes(self,orderKey):
        codes = self.db.selectAll("substring(code,8,1)="+orderKey+"","substring(code,3)",True)
        codelist = []
        for obj in codes:
            codelist.append(obj['id'])
        return codelist

    def getCodesUnExec(self):
        return self.db.selectAll("exec_status=0","*",True)

    def getGaiNain(self, code):
        url = "http://push2.eastmoney.com/api/qt/slist/get?pn=1&pz=6&po=1" \
              "&fid=f3&spt=3&fields=f1%2Cf2%2Cf3%2Cf12%2Cf13%2Cf14%2Cf152&secid=" + self.translateDfcfCode(code) + "&invt=2&fltt=2&_=1620524222775"
        try:
            response = httpx.get(url, headers=self.headers, verify=False, timeout=5)
            data = response.json()
            if data['rc'] == 102:
                return False
            else:
                hy = []
                hyinfo = data['data']['diff']
                if hyinfo != False:
                    for i in hyinfo:
                        hy.append(hyinfo[i]["f14"])
                return hy
        except:
            return False

    def getDetail(self,code):
        stock_individual_info_em_df = ak.stock_individual_info_em(symbol=code)
        return self.translateDfToMap(stock_individual_info_em_df)

    def getInfoByCode(self,code):
        return self.db.selectAll("substr(code,3)='"+code+"'","*",True)

    def getCode(self,code):
        return self.db.selectAll("code='"+code+"'","*",True)

    def initTask(self):
        sql = "update codes set lockid=0,exec_status=0"
        return self.db.executeUpdate(sql)

    def getAutoSelect(self):
        sql = "select a.* from codes a left join (select * from auto_select where logday in (select max(logday) from auto_select)) b on a.code=b.code where b.code is not null;"
        return self.db.executeMap(sql)

    def getStockSelect(self):
        sql = "select a.code,a.codename,a.industry,a.gainian,a.flow_money,a.maxval20,a.pre_close,b.alert_price from codes a left join stock_select b on a.code=b.code where b.code is not null;"
        return self.db.executeToMap(sql,["code","codename","industry","gainian","flow_money","maxval20","pre_close","alert_price"],"")


    def getPriceDetail(self,code):
        redis = RedisUtil()
        stockbaseinfo = StockBaseInfo()
        #txt = "概念板块： " + stockbaseinfo.getGaiNian(code) + "<br>--------------------------------------------<br>"
        key = "dfcf_data_" + str(code)
        al = redis.vget(key)
        if al == None:
            print("=================set cache=======================")
            klineday = stockbaseinfo.getDfcfLineDay(code, 30)
            al = json.dumps(klineday)
            redis.vset(key, al)
        else:
            print("=======read cache===============")
            print(al)
        zf = 0
        klineday = json.loads(al)
        if "klines" in klineday:
            data = []
            pre_close = 1
            for row in klineday["klines"]:
                daydata = row.split(",")
                info = {
                    "code": code,
                    "trade_date": daydata[0],
                    "open": daydata[1],
                    "high": daydata[3],
                    "low": daydata[4],
                    "close": daydata[2],
                    "volume": round(float(daydata[5])/10000, 2),
                    "money": round(float(daydata[6])/100000000, 2),
                    "zf": daydata[8],
                    "zfprice": daydata[9],
                    "turn": daydata[10]
                }
                data.append(info)
            df = pd.DataFrame(data)
            df.set_index("trade_date", inplace=True)
            df_sorted = df.sort_index(ascending=True)
            newdata = []
            pre_close = 1
            i = 0
            base_price = 0
            base_vol = 0
            close_data = []
            x_data = []
            dis_close_rate = []
            dis_vol_rate = []
            for index, row in df_sorted.iterrows():
                if i == 0:
                    base_price = row["close"]
                    base_vol = row["volume"]
                info = {
                    "code": row["code"],
                    "trade_date": index,
                    "open": row["open"],
                    "high": row["high"],
                    "low": row["low"],
                    "close": row["close"],
                    "volume": row["volume"],
                    "money": row["money"],
                    "turn": row["turn"],
                    "preclose": pre_close,
                    "zf": round((float(row["close"]) - float(pre_close)) * 100 / float(pre_close), 2),
                    "dis_close": float(row["close"]) - float(base_price),
                    "dis_close_rate": round((float(row["close"]) - float(base_price)) / float(base_price), 2),
                    "dis_vol": float(row["volume"]) - float(base_vol),
                    "dis_vol_rate": round((float(row["volume"]) - float(base_vol)) / float(base_vol), 2)
                }
                x_data.append(index)
                close_data.append(row["close"])
                dis_close_rate.append(info["dis_close_rate"] * 20)
                dis_vol_rate.append(info["dis_vol_rate"])
                pre_close = row["close"]
                newdata.append(info)
                i += 1
            newdfdata = pd.DataFrame(newdata)
            ma_list = [5, 10, 20]
            for ma in ma_list:
                newdfdata['close_ma_' + str(ma)] = newdfdata["close"].rolling(ma).mean()
            for ma in ma_list:
                newdfdata['volume_ma_' + str(ma)] = newdfdata["volume"].rolling(ma).mean()
            allzf = round(newdfdata["zf"].tail(5).sum(),2)

            xs = [datetime.datetime.strptime(d, '%Y-%m-%d').date() for d in x_data]

            # 创建图像和轴
            fig, ax = plt.subplots()

            # 绘制第一条折线
            ax.plot(xs, close_data, label='close')

            # 绘制第二条折线
            ax.plot(xs, dis_close_rate, label='dis_close_rate')

            # 绘制第二条折线
            ax.plot(xs, dis_vol_rate, label='dis_vol_rate')

            plt.tick_params(axis='both', which='both', labelsize=10)

            # 显示折线图
            plt.gcf().autofmt_xdate()  # 自动旋转日期标记

            # 创建Locator对象
            y_locator = MultipleLocator(2)

            # 设置y轴刻度间隔
            plt.gca().yaxis.set_major_locator(y_locator)

            # 显示图例
            ax.legend()

            # 显示图像
            plt.show()

    def addExange(self,actid,type,close,code,exchage_date):
        detailService = AccountDetailService()
        moneyInfo = detailService.getAccount(actid)
        print(moneyInfo)
        money = moneyInfo[0]["hand_money"]
        userid = moneyInfo[0]["userid"]
        exchangeService = AccountExchangeService()
        holdDetailService = StockHoldsDetailService()
        info = {
            "userid": userid,
            "actid": actid,
            "exchange_time":exchage_date,
            "code": code
        }
        if type == "buy":
            info["buy_price"] = close
            info["buy_num"] = int(float(money)/(float(close)*100))*100
            info["buy_time"] = exchage_date
            holdinfo = {
                "userid": userid,
                "code": code,
                "actid": actid,
                "buy_price": info["buy_price"],
                "buy_num": info["buy_num"],
                "buy_time": info["buy_time"]
            }
            holdDetailService.addDetail(holdinfo)
            detailService.updateAccount(actid,float(money)-float(info["buy_num"])*float(close))
        else:
            detailInfo = holdDetailService.getDetail(actid,code)
            print(detailInfo)
            if detailInfo != None and len(detailInfo) > 0:
                info["sell_price"] = close
                info["sell_num"] = detailInfo[0]["buy_num"]
                info["sell_time"] = exchage_date
                holdDetailService.deleteDetail(actid,code)
                detailService.updateAccount(actid, float(money) + float(info["sell_num"]) * float(close))
        exchangeService.addExchange(info)

    def getHoldFlat(self,actid):
        holdDetailService = StockHoldsDetailService()
        rs = holdDetailService.getAllDetail(actid)
        if len(rs) > 0:
            return rs[0]["code"]
        else:
            return False

    def getRunPrice(self,codes,actid):
        redis = RedisUtil()
        stockbaseinfo = StockBaseInfo()
        #txt = "概念板块： " + stockbaseinfo.getGaiNian(code) + "<br>--------------------------------------------<br>"
        datas = {}
        dates = []
        m = 0
        for code in codes:
            key = "dfcf_data_" + str(code)
            al = redis.vget(key)
            if al == None:
                print("=================set cache=======================")
                klineday = stockbaseinfo.getDfcfLineDay(code, 30)
                al = json.dumps(klineday)
                redis.vset(key, al)
            else:
                print("=======read cache===============")
                print(al)
            klineday = json.loads(al)
            if "klines" in klineday:
                data = []
                for row in klineday["klines"]:
                    daydata = row.split(",")
                    if m == 0:
                        dates.append(daydata[0])
                    info = {
                        "code": code,
                        "trade_date": daydata[0],
                        "open": daydata[1],
                        "high": daydata[3],
                        "low": daydata[4],
                        "close": daydata[2],
                        "volume": round(float(daydata[5]) / 10000, 2),
                        "money": round(float(daydata[6]) / 100000000, 2),
                        "zf": float(daydata[8]),
                        "zfprice": daydata[9],
                        "turn": daydata[10]
                    }
                    data.append(info)
                newdfdata = pd.DataFrame(data)
                ma_list = [5, 10, 20]
                for ma in ma_list:
                    newdfdata['close_ma_' + str(ma)] = newdfdata["close"].rolling(ma).mean()
                for ma in ma_list:
                    newdfdata['volume_ma_' + str(ma)] = newdfdata["volume"].rolling(ma).mean()
                newdfdata.set_index("trade_date", inplace=True)
                df_sorted = newdfdata.sort_index(ascending=True)
                datas[code] = df_sorted
            m += 1
        print(datas)
        print(dates)
        holdflag = False
        lastcode = ""
        circleflag = True
        for day in dates:
            for code in codes:
                #如果不循环，只查对应的code
                if circleflag == False and code != lastcode:
                    continue
                line = datas[code]
                row = line.loc[day]
                if row['close_ma_5'] != None and float(row["close"]) > float(row["close_ma_5"]):
                    if holdflag == False:
                        print(day)
                        print("买入")
                        holdflag = True
                        self.addExange(actid, "buy", row["close"], code, day)
                        circleflag = False
                        lastcode = code
                        break
                    else:
                        print(day)
                        print("持有")

                elif row['close_ma_5'] != None and float(row["close"]) < float(row["close_ma_5"]):
                    if holdflag == True:
                        print(day)
                        print("卖出")
                        holdflag = False
                        self.addExange(actid, "sell", row["close"], code, day)
                        circleflag = True
                        lastcode = code
                    else:
                        print(day)
                        print("空仓")

    def getPrice(self,codes,actid):
        redis = RedisUtil()
        stockbaseinfo = StockBaseInfo()
        #txt = "概念板块： " + stockbaseinfo.getGaiNian(code) + "<br>--------------------------------------------<br>"
        datas = {}
        dates = []
        m = 0
        for code in codes:
            klineday = stockbaseinfo.getDfcfLineDay(code, 30)
            """
            al = json.dumps(klineday)            
            key = "dfcf_data_" + str(code)
            al = redis.vget(key)
            
            if al == None:
                print("=================set cache=======================")
                klineday = stockbaseinfo.getDfcfLineDay(code, 30)
                al = json.dumps(klineday)
                redis.vset(key, al)
            else:
                print("=======read cache===============")
                print(al)            
            klineday = json.loads(al)
            """
            if "klines" in klineday:
                data = []
                for row in klineday["klines"]:
                    daydata = row.split(",")
                    if m == 0:
                        dates.append(daydata[0])
                    info = {
                        "code": code,
                        "trade_date": daydata[0],
                        "open": daydata[1],
                        "high": daydata[3],
                        "low": daydata[4],
                        "close": daydata[2],
                        "volume": round(float(daydata[5]) / 10000, 2),
                        "money": round(float(daydata[6]) / 100000000, 2),
                        "zf": float(daydata[8]),
                        "zfprice": daydata[9],
                        "turn": daydata[10]
                    }
                    data.append(info)
                newdfdata = pd.DataFrame(data)
                ma_list = [5, 10, 20]
                for ma in ma_list:
                    newdfdata['close_ma_' + str(ma)] = newdfdata["close"].rolling(ma).mean()
                for ma in ma_list:
                    newdfdata['volume_ma_' + str(ma)] = newdfdata["volume"].rolling(ma).mean()
                newdfdata.set_index("trade_date", inplace=True)
                df_sorted = newdfdata.sort_index(ascending=True)
                datas[code] = df_sorted
            m += 1
        holdcode = self.getHoldFlat(actid)
        print("===========holdcode=============")
        print(holdcode)
        if holdcode == False:
            holdflag = False
        else:
            holdflag = True
        for day in dates:
            if day != self.today:
                continue
            for code in codes:
                #如果不循环，只查对应的code
                if holdflag == True and code != holdcode:
                    continue
                line = datas[code]
                row = line.loc[day]
                if row['close_ma_5'] != None and float(row["close"]) > float(row["close_ma_5"]) and float(row["volume"]) > (float(row["volume_ma_5"])/2):
                    if holdflag == False:
                        print(day)
                        print("买入")
                        holdflag = True
                        self.addExange(actid, "buy", row["close"], code, day)
                        break
                    else:
                        print(day)
                        print("持有")
                elif row['close_ma_5'] != None and float(row["close"]) < float(row["close_ma_5"]):
                    if holdflag == True:
                        print(day)
                        print("卖出")
                        holdflag = False
                        self.addExange(actid, "sell", row["close"], code, day)
                        break
                    else:
                        print(day)
                        print("空仓")

